<?php

namespace app\index\controller;

use app\BaseController;
use think\facade\Lang;
use think\facade\Config;
use think\facade\Db;
use fast\Random;
use PDO;
use Exception;
use PDOException;

use function PHPSTORM_META\map;

class Install extends BaseController
{
    /**
     * 最低PHP版本
     * @var string
     */
    protected $minPhpVersion = '8.0.0';

    public function index()
    {
        $lang = Lang::getLangSet();
        $lang = preg_match("/^([a-zA-Z\-_]{2,10})\$/i", $lang) ? $lang : 'zh-cn';

        if (!$lang || in_array($lang, ['zh-cn', 'zh-hans-cn'])) {
            Lang::load(app_path() . '/index/lang/install/zh-cn.php');
        }

        $installLockFile = root_path() . 'config/install/lock/' . "install.lock";

        if (is_file($installLockFile)) {
            return '当前已经安装成功，如果需要重新安装，请手动移除install.lock文件';
            
        }

        $output = function ($code, $msg, $url = null, $data = null) {
            return json(['code' => $code, 'msg' => $msg, 'url' => $url, 'data' => $data]);
        };

        if ($this->request->isPost()) {
            $mysqlHostname = $this->request->post('mysqlHostname', '127.0.0.1');
            $mysqlHostport = $this->request->post('mysqlHostport', '3306');
            $hostArr = explode(':', $mysqlHostname);

            if (count($hostArr) > 1) {
                $mysqlHostname = $hostArr[0];
                $mysqlHostport = $hostArr[1];
            }

            $mysqlUsername = $this->request->post('mysqlUsername', 'root');
            $mysqlPassword = $this->request->post('mysqlPassword', '');
            $mysqlDatabase = $this->request->post('mysqlDatabase', '');
            $mysqlPrefix = $this->request->post('mysqlPrefix', 'fa_');
            $adminUsername = $this->request->post('adminUsername', 'admin');
            $adminPassword = $this->request->post('adminPassword', '');
            $adminPasswordConfirmation = $this->request->post('adminPasswordConfirmation', '');
            $adminEmail = $this->request->post('adminEmail', 'admin@admin.com');
            $siteName = $this->request->post('siteName', '我的网站');

            if ($adminPassword !== $adminPasswordConfirmation) {
                return $output(0, '两次输入的密码不一致');
            }

            $adminName = '';

            try {
                $adminName = $this->installation($mysqlHostname, $mysqlHostport, $mysqlDatabase, $mysqlUsername, $mysqlPassword, $mysqlPrefix, $adminUsername, $adminPassword, $adminEmail, $siteName);
            } catch (PDOException $e) {
                throw new Exception($e->getMessage());
            } catch (\Exception $e) {
                return $output(0, $e->getMessage());
            }
            return $output(1, '安装成功！', null, ['adminName' => $adminName]);
        }

        $errInfo = '';
        return $this->fetch('', ['errInfo' => $errInfo]);
    }

    /**
     * 执行安装
     */
    protected function installation($mysqlHostname, $mysqlHostport, $mysqlDatabase, $mysqlUsername, $mysqlPassword, $mysqlPrefix, $adminUsername, $adminPassword, $adminEmail = null, $siteName = null)
    {
        $this->checkenv();

        if ($mysqlDatabase == '') {
            throw new Exception('请输入正确的数据库名');
        }
        if (!preg_match("/^\w{3,12}$/", $adminUsername)) {
            throw new Exception('用户名只能由3-30位数字、字母、下划线组合');
        }
        if (!preg_match("/^[\S]{6,16}$/", $adminPassword)) {
            throw new Exception('密码长度必须在6-30位之间，不能包含空格');
        }
        $weakPasswordArr = ['123456', '12345678', '123456789', '654321', '111111', '000000', 'password', 'qwerty', 'abc123', '1qaz2wsx'];
        if (in_array($adminPassword, $weakPasswordArr)) {
            throw new Exception('密码太简单，请重新输入');
        }
        if ($siteName == '' || preg_match("/fast" . "admin/i", $siteName)) {
            throw new Exception('网站名称输入不正确');
        }

        $sql = file_get_contents(root_path() . 'config/install/sql/' . 'install.sql');

        $sql = str_replace("`fa_", "`{$mysqlPrefix}", $sql);

        // 先尝试能否自动创建数据库
        $type = Config::get('database.default');
        
        try {
            $pdo = new PDO("{$type}:host={$mysqlHostname}" . ($mysqlHostport ? ";port={$mysqlHostport}" : ''), $mysqlUsername, $mysqlPassword);
            $pdo->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
            $pdo->query("CREATE DATABASE IF NOT EXISTS `{$mysqlDatabase}` CHARACTER SET utf8mb4 COLLATE utf8mb4_general_ci;");

            $connections = [
                'install' => [
                    'type'     => "{$type}",
                    'hostname' => "{$mysqlHostname}",
                    'hostport' => "{$mysqlHostport}",
                    'database' => "{$mysqlDatabase}",
                    'username' => "{$mysqlUsername}",
                    'password' => "{$mysqlPassword}",
                    'prefix'   => "{$mysqlPrefix}"
                ]
            ];
            Config::set([
                'connections' => $connections
            ], 'database');
            // 连接install命令中指定的数据库
            $instance = Db::connect('install');

            // 查询一次SQL,判断连接是否正常
            $instance->execute("SELECT 1");

            // 调用原生PDO对象进行批量查询
            $instance->getPdo()->exec($sql);
        } catch (\PDOException $e) {
            throw new Exception($e->getMessage());
        }

        

        $envText = $this->array_env_string([
            'APP_DEBUG' => false,
            'database' => [
                'type' => $type,
                'host' => $mysqlHostname,
                'name' => $mysqlDatabase,
                'user' => $mysqlUsername,
                'pass' => $mysqlPassword,
                'port' => 3306,
                'charset' => 'utf8',
                'prefix' => $mysqlPrefix,
            ],
            'lang' => [
                'default' => 'zh-cn',
            ],
            'conf' => [
                'admin_path' => 'admin'
            ]
        ]);
        // 数据库配置文件
        $envFile = root_path() . '.env';
        
        // 检测能否成功写入数据库配置
        $result = @file_put_contents($envFile, $envText);
        if (!$result) {
            throw new Exception('当前权限不足，无法写入文件.env');
        }

        $avatar = '/assets/img/avatar.png';
        // 变更默认管理员密码
        $adminPassword = $adminPassword ? $adminPassword : Random::alnum(8);
        $adminEmail = $adminEmail ? $adminEmail : "admin@admin.com";
        $newSalt = substr(md5(uniqid(true)), 0, 6);
        $newPassword = md5(md5($adminPassword) . $newSalt);
        $data = ['username' => $adminUsername, 'email' => $adminEmail, 'avatar' => $avatar, 'password' => $newPassword, 'salt' => $newSalt];
        $instance->name('admin')->where('username', 'admin')->update($data);


        $installLockFile = root_path() . 'config/install/lock/' . "install.lock";
        //检测能否成功写入lock文件
        $result = @file_put_contents($installLockFile, date('Y-m-d H:i:s'));
        if (!$result) {
            throw new Exception('当前权限不足，无法写入文件application/admin/command/Install/install.lock');
        }
    }

    /**
     * 检测环境
     */
    protected function checkenv()
    {
        if (version_compare(PHP_VERSION, $this->minPhpVersion, '<')) {
            throw new Exception('当前版本PHP ' . PHP_VERSION . '过低，请使用PHP ' . $this->minPhpVersion . '及以上版本');
        }
        if (!extension_loaded("PDO")) {
            throw new Exception('当前未开启PDO，无法进行安装');
        }
        return true;
    }

    public function array_env_string(array $arr, int $level = 0): string
    {
        $env_string = '';
        foreach($arr as $k => $v) {
            if (is_array($v)) {
                $env_string .= '[' . $k . ']' . PHP_EOL;
                $env_string .= $this->array_env_string($v, $level + 1) . PHP_EOL;
            } else {
                $env_string .= ($level === 0 ? '' : '    ') . $k . '=' . trim(var_export($v, true), '\'') . '' . PHP_EOL;
            }
        }

        return $env_string;
    }


}